package com.fowo.api.sys.service.impl;

import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.fowo.api.sys.entity.SysRoleData2;
import com.fowo.api.sys.entity.SysRoleData2Field;
import com.fowo.api.sys.entity.SysRoleData2Funcs;
import com.fowo.api.sys.entity.SysRoleData2Group;
import com.fowo.api.sys.mapper.SysRoleData2FieldMapper;
import com.fowo.api.sys.mapper.SysRoleData2FuncsMapper;
import com.fowo.api.sys.mapper.SysRoleData2GroupMapper;
import com.fowo.api.sys.mapper.SysRoleData2Mapper;
import com.fowo.api.sys.model.RoleFieldItem;
import com.fowo.api.sys.model.SysRoleData2Map;
import com.fowo.api.sys.service.SysRoleData2Service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统角色数据权限版本2服务实现
 * @author yl_ls
 */
@Service
public class SysRoleData2ServiceImpl implements SysRoleData2Service {
    @Resource
    private SysRoleData2GroupMapper groupMapper;
    @Resource
    private SysRoleData2FuncsMapper funcsMapper;
    @Resource
    private SysRoleData2FieldMapper fieldMapper;
    @Resource
    private SysRoleData2Mapper mapper;
    private final IdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator();

    @Override
    public List<SysRoleData2Group> getGroups() {
        return groupMapper.selectList();
    }

    @Override
    public List<SysRoleData2Funcs> getFuncs() {
        return funcsMapper.selectList();
    }

    @Override
    public List<SysRoleData2Field> getFields() {
        return fieldMapper.selectList();
    }

    @Override
    public SysRoleData2Map getDataMap(Long roleId, Long groupId) {
        List<SysRoleData2> data = mapper.selectFast(roleId, groupId);
        Map<String, List<SysRoleData2>> typeList = data.stream().collect(Collectors.groupingBy(SysRoleData2::getTargetType));

        SysRoleData2Map map = new SysRoleData2Map();
        for (Map.Entry<String, List<SysRoleData2>> stringListEntry : typeList.entrySet()) {
            map.put(stringListEntry.getKey(), stringListEntry.getValue().stream().map(SysRoleData2::getTargetId).collect(Collectors.toList()));
        }
        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setDataMap(Long roleId, Long groupId, SysRoleData2Map data) {
        List<SysRoleData2> list = mapper.selectList(roleId, groupId);

        List<SysRoleData2> deleted = list.stream().filter(d -> data.entrySet().stream().noneMatch(
                u -> Objects.equals(u.getKey(), d.getTargetType())
                        && u.getValue().contains(d.getTargetId())
        )).collect(Collectors.toList());
        if (!deleted.isEmpty()) {
            mapper.batchDelete(deleted.stream().map(SysRoleData2::getId).collect(Collectors.toList()));
        }

        List<SysRoleData2> inserted = new ArrayList<>();
        for (Map.Entry<String, List<Long>> typeIdsEntry : data.entrySet()) {
            for (Long targetId : typeIdsEntry.getValue()) {
                if (list.stream().noneMatch(u ->
                        Objects.equals(u.getTargetType(), typeIdsEntry.getKey())
                        && Objects.equals(u.getTargetId(), targetId)
                )) {
                    SysRoleData2 newData2 = new SysRoleData2();
                    newData2.setId((Long) identifierGenerator.nextId(null));
                    newData2.setRoleId(roleId);
                    newData2.setGroupId(groupId);
                    newData2.setTargetType(typeIdsEntry.getKey());
                    newData2.setTargetId(targetId);
                    inserted.add(newData2);
                }
            }
        }

        if (!inserted.isEmpty()) {
            mapper.batchInsert(inserted);
        }
    }

    @Override
    public List<RoleFieldItem> getFieldsByRoleId(Long roleId) {
        return fieldMapper.selectItemsByRoleId(roleId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateFieldsByRoleId(Long roleId, List<RoleFieldItem> items) {
        List<SysRoleData2Field> fields = getFields();
        List<SysRoleData2> roleFields = mapper.selectListByRoleIdAndTargetType(roleId, "field");
        Map<String, SysRoleData2Field> fieldNameMap = new HashMap<>();
        Map<Long, SysRoleData2Field> fieldIdMap = new HashMap<>();
        fields.forEach(f -> {
            fieldNameMap.put(f.getName(), f);
            fieldIdMap.put(f.getId(), f);
        });

        List<SysRoleData2> deleted = new ArrayList<>();
        List<SysRoleData2> updated = new ArrayList<>();
        List<SysRoleData2> inserted = new ArrayList<>();

        for (SysRoleData2 oldRoleField : roleFields) {
            SysRoleData2Field sysRoleData2Field = fieldIdMap.get(oldRoleField.getTargetId());
            if (sysRoleData2Field == null) {
                // 一个老的选项字段未找到，忽略不做任何操作
                continue;
            }
            items.stream().filter(i -> Objects.equals(i.getName(), sysRoleData2Field.getName())).findFirst().ifPresentOrElse(ni -> {
                // 更新选项
                if (!Objects.equals(ni.getValue(), oldRoleField.getTargetData())) {
                    // 变更了值，需要更新
                    SysRoleData2 updatedItem = new SysRoleData2();
                    updatedItem.setId(oldRoleField.getId());
                    updatedItem.setTargetData(ni.getValue());
                    updated.add(updatedItem);
                }
            }, () -> {
                // 新配置中没找到，需要删除
                deleted.add(oldRoleField);
            });
        }
        for (RoleFieldItem item : items) {
            SysRoleData2Field sysRoleData2Field = fieldNameMap.get(item.getName());
            if (sysRoleData2Field == null) {
                // 一个新的选项字段未找到，忽略不做任何操作
                continue;
            }
            if (roleFields.stream().noneMatch(r -> Objects.equals(r.getTargetId(), sysRoleData2Field.getId()))) {
                // 老配置中不存在，需要重建
                SysRoleData2 insertedItem = new SysRoleData2();
                insertedItem.setId((Long) identifierGenerator.nextId(null));
                insertedItem.setRoleId(roleId);
                insertedItem.setTargetType("field");
                insertedItem.setTargetId(sysRoleData2Field.getId());
                insertedItem.setTargetData(item.getValue());
                insertedItem.setGroupId(0L);
                inserted.add(insertedItem);
            }
        }

        // 提交数据
        if (!deleted.isEmpty()) {
            mapper.batchDelete(deleted.stream().map(SysRoleData2::getId).collect(Collectors.toList()));
        }
        if (!updated.isEmpty()) {
            updated.forEach(mapper::updateById);
        }
        if (!inserted.isEmpty()) {
            mapper.batchInsert(inserted);
        }
    }
}
